package com.hh.demo.service.impl;

import com.hh.demo.doc.CourseDoc;
import com.hh.demo.dto.CourseSearchDto;
import com.hh.demo.esmapper.HighlightResultMapper;
import com.hh.demo.repository.CourseEsRepository;
import com.hh.demo.result.PageList;
import com.hh.demo.service.ICourseEsService;
import com.hh.demo.vo.AggrBucket;
import com.hh.demo.vo.AggrPageList;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class CourseEsServiceImpl implements ICourseEsService {
    @Resource
    private CourseEsRepository courseEsRepository;
    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;
    @Resource
    private HighlightResultMapper highlightResultMapper;



    @Override
    public void saveCourse(CourseDoc doc) {
         courseEsRepository.save(doc);
    }

    @Override
    public void deleteCourse(Long id) {
        courseEsRepository.deleteById(id);
    }

    @Override
    public AggrPageList<CourseDoc> search(CourseSearchDto dto) {
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        //排序
        String sortField = dto.getSortField();
        if (!StringUtils.isEmpty(sortField)){
            //准备好排序的字段名
            switch (sortField.toLowerCase()){
                case "xl" : sortField="saleCount";
                    break;
                case "xp" : sortField="onlineTime";
                    break;
                case "pl" : sortField="commentCount";
                    break;
                case "jg" : sortField="price";
                    break;
                case "rq" : sortField="viewCount";
                    break;
            }
            //排序类型：正序or倒序
            String sortType = dto.getSortType();
            if (!StringUtils.isEmpty(sortType)){
                SortOrder sortOrder = sortType.equalsIgnoreCase("asc") ? SortOrder.ASC : SortOrder.DESC;
                //封装排序条件
                builder.withSort(new FieldSortBuilder(sortField).order(sortOrder));
            }
        }
        //分页
        //封装分页条件,从0开始
        builder.withPageable(PageRequest.of(dto.getPage()-1,dto.getRows()));

        //查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if(!StringUtils.isEmpty(dto.getKeyword())){
            boolQuery.must(QueryBuilders.matchQuery("name",dto.getKeyword()));
        }
        if(dto.getCourseTypeId()!=null){
            boolQuery.filter(QueryBuilders.termQuery("courseTypeId",dto.getCourseTypeId()));
        }
        if(!StringUtils.isEmpty(dto.getGradeName())){
            boolQuery.filter(QueryBuilders.termQuery("gradeName",dto.getGradeName()));
        }
        if(!StringUtils.isEmpty(dto.getChargeName())){
            boolQuery.filter(QueryBuilders.termQuery("chargeName",dto.getChargeName()));
        }
        if(dto.getPriceMin() != null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(dto.getPriceMin()));
        }
        if(dto.getPriceMax() != null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").lte(dto.getPriceMax()));
        }
        //封装查询条件
        builder.withQuery(boolQuery);

        //添加聚合条件，课程等级和是否收费
        builder.addAggregation(AggregationBuilders.terms("aggGradeName").field("gradeName"));
        builder.addAggregation(AggregationBuilders.terms("aggChargeName").field("chargeName"));

        //关键字高亮
        builder.withHighlightFields(new HighlightBuilder.Field("name")
                .preTags("<font style='color:blue'>")
                .postTags("</font>")
        );

        //springboot项目使用关键字高亮，需要用elasticsearchRestTemplate
        //Page<CourseDoc> page = courseEsRepository.search(builder.build());
        AggregatedPage<CourseDoc> page = elasticsearchRestTemplate.queryForPage(builder.build(), CourseDoc.class, highlightResultMapper);


        //所有的聚合结果，转为map，key就是添加的时候的别名
        Map<String, Aggregation> aggregationMap = page.getAggregations().asMap();
        ParsedStringTerms aggGradeName = (ParsedStringTerms)aggregationMap.get("aggGradeName");
        ParsedStringTerms aggChargeName = (ParsedStringTerms)aggregationMap.get("aggChargeName");

        //将这个结果转成我们想要的List<AggrBucket>
        List<AggrBucket> aggGradeNameList = aggGradeName.getBuckets().stream()
                .map(bucket -> new AggrBucket(bucket.getKeyAsString(), bucket.getDocCount()))
                .collect(Collectors.toList());
        List<AggrBucket> aggChargeNameList = aggChargeName.getBuckets().stream()
                .map(bucket -> new AggrBucket(bucket.getKeyAsString(), bucket.getDocCount()))
                .collect(Collectors.toList());

        Map<String, List<AggrBucket>> aggResult = new HashMap<>();
        aggResult.put("aggGradeName",aggGradeNameList);
        aggResult.put("aggChargeName",aggChargeNameList);
        return new AggrPageList<>(page.getTotalElements(),page.getContent(),aggResult);
    }
}